//
//  HYLevelScene.m
//  SpriteKitDemo
//
//  Created by yanghaha on 16/4/4.
//  Copyright © 2016年 hillyoung. All rights reserved.
//

#import "HYLevelScene.h"
#import "HYPlayerNode.h"
#import "HYEnemyNode.h"
#import "HYBulletNode.h"

#define ARC4RANDOM_MAX 0x100000000

@interface HYLevelScene ()

@property (strong, nonatomic) HYPlayerNode *playerNode;
@property (strong, nonatomic) SKNode *enemies;
@property (strong, nonatomic) SKNode *playerBullets;

@end

@implementation HYLevelScene

+ (instancetype)sceneWithSize:(CGSize)size levelNumber:(NSUInteger)levelNumber {
    return [[self alloc] initWithSize:size levelNumber:levelNumber];
}

- (instancetype)initWithSize:(CGSize)size {
    return [self initWithSize:size levelNumber:1];
}

- (instancetype)initWithSize:(CGSize)size levelNumber:(NSUInteger)levelNumber {
    self = [super initWithSize:size];

    if (self) {
        _levelNumber = levelNumber;
        _playerLives = 5;
        self.backgroundColor = [SKColor whiteColor];

        SKLabelNode *lives = [SKLabelNode labelNodeWithFontNamed:@"Courier"];
        lives.fontSize = 16;
        lives.fontColor = [SKColor blackColor];
        lives.name = @"LivesLabel";
        lives.text = [NSString stringWithFormat:@"Lives: %lu", (unsigned long)_playerLives];
        lives.verticalAlignmentMode = SKLabelVerticalAlignmentModeTop;
        lives.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeRight;
        lives.position = CGPointMake(CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));
        [self addChild:lives];

        SKLabelNode *level = [SKLabelNode labelNodeWithFontNamed:@"Courier"];
        level.fontSize = 16;
        level.fontColor = [UIColor blackColor];
        level.name = @"LevelLabel";
        level.text = [NSString stringWithFormat:@"Level: %lu", (NSUInteger)_levelNumber];
        level.verticalAlignmentMode = SKLabelVerticalAlignmentModeTop;
        level.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeRight;
        level.position = CGPointMake(100, CGRectGetHeight(self.frame));
        [self addChild:level];

        _playerNode = [HYPlayerNode node];
        _playerNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetHeight(self.frame)*.1);
        [self addChild:_playerNode];

        _enemies = [SKNode node];
        [self addChild:_enemies];

        _playerBullets = [SKNode node];
        [self addChild:_playerBullets];

        [self spawnEnemies];

        self.physicsWorld.gravity = CGVectorMake(0, -1);
        self.physicsWorld.contactDelegate = self;
    }

    return self;
}

#pragma mark - Private

- (void)setPlayerLives:(NSUInteger)playerLives {
    _playerLives = playerLives;

    SKLabelNode *lives = (id)[self childNodeWithName:@"LivesLabel"];
    lives.text = [NSString stringWithFormat:@"Lives: %lu", (unsigned long)_playerLives];
}

- (void)spawnEnemies {

    NSUInteger count = log(self.levelNumber)+self.levelNumber;
    for (int i=0; i<count; i++) {
        HYEnemyNode *enemy = [HYEnemyNode node];
        CGSize size = self.frame.size;
        CGFloat x = (size.width*.8*arc4random())/ARC4RANDOM_MAX+(size.width*.1);
        CGFloat y = (size.height*.5*arc4random()/ARC4RANDOM_MAX)+(size.height*.5);
        enemy.position = CGPointMake(x, y);
        [self.enemies addChild:enemy];
    }
}

- (void)update:(NSTimeInterval)currentTime {
    [self updateBullets];
    [self updateEnemies];
    [self checkForNextLevel];
}

- (void)updateBullets {
    NSMutableArray *bulletsToRemove = [NSMutableArray array];
    for (HYBulletNode *bullet in self.playerBullets.children) {
        if (!CGRectContainsPoint(self.frame, bullet.position)) {
            [bulletsToRemove addObject:bullet];
            continue;
        }

        [bullet applyRecurringForce];
    }

    [self.playerBullets removeChildrenInArray:bulletsToRemove];
}

- (void)updateEnemies {
    NSMutableArray *enemiesToRemove = [NSMutableArray array];
    for (SKNode *node in self.enemies.children) {
        if (!CGRectContainsPoint(self.frame, node.position)) {
            [enemiesToRemove addObject:node];
            continue;
        }
    }

    if (enemiesToRemove.count > 0) {
        [self.enemies removeChildrenInArray:enemiesToRemove];
    }
}

- (void)checkForNextLevel {
    if (self.enemies.children.count == 0) {
        [self goToNextLevel];
    }
}

- (void)goToNextLevel {
    self.finised = YES;

    SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:@"Courier"];
    label.text = @"Level Complete!";
    label.fontColor = [SKColor blueColor];
    label.fontSize = 32;
    label.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    [self addChild:label];

    HYLevelScene *nextLevel = [[HYLevelScene alloc] initWithSize:self.frame.size levelNumber:self.levelNumber+1];
    [self.view presentScene:nextLevel transition:[SKTransition flipVerticalWithDuration:1.]];
}

#pragma mark - Touch

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];
        if (location.y < CGRectGetHeight(self.frame)*.2) {
            CGPoint targetPoint = CGPointMake(location.x, self.playerNode.position.y);
            [self.playerNode moveToward:targetPoint];
        } else {
            HYBulletNode *bullet = [HYBulletNode bulletFrom:self.playerNode.position toward:location];
            if (bullet) {
                [self.playerBullets addChild:bullet];
            }
        }
    }
}

#pragma mark - SKPhysicsContactDelegate

- (void)didBeginContact:(SKPhysicsContact *)contact {
    if (contact.bodyA.categoryBitMask == contact.bodyB.categoryBitMask) {
        SKNode *nodeA = contact.bodyA.node;
        SKNode *nodeB = contact.bodyB.node;

        [nodeA friendlyBumpFrom:nodeB];
        [nodeB friendlyBumpFrom:nodeA];
    } else {
        SKNode *attacker = nil;
        SKNode *attackee = nil;

        if (contact.bodyA.categoryBitMask > contact.bodyB.categoryBitMask) {
            attacker = contact.bodyA.node;
            attackee = contact.bodyB.node;
        } else {
            attacker = contact.bodyB.node;
            attackee = contact.bodyA.node;
        }

        if ([attackee isKindOfClass:[HYPlayerNode class]]) {
            self.playerLives--;
        }

        if (attacker) {
            [attackee receiveAttacker:attacker contact:contact];
            [self.playerBullets removeChildrenInArray:@[attacker]];
            [self.enemies removeChildrenInArray:@[attacker]];
        }
    }
}

@end
